/*
 * Cliente de Ping UDP.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#include "pingudp.h"

/*Variaveis globais, guardam valores uteis na funcao de sair.*/
double soma, menorPing, maiorPing;
int i;

/*Funcao chamada apertando CTRL+\, sai do programa e exibe dados finais.*/
void sair(){

    printf("\nSaida chamada.\n"
    "Menor PING: %.3lfms\nPING medio: %.3lfms\nMaior PING: %.3lfms\n",
     menorPing, (soma/(i+1)), maiorPing);
    exit(0);

}

int main(int argc, char *argv[]) {
	int sock, aux, i;
	struct sockaddr_in addr;
	unsigned int size = sizeof addr;
	char msg[LEN] = MSG;
	struct timeval tempo, tempo2;
	float tempoPing;

	/*Prepara o sinal de saida.*/
	signal(SIGQUIT,sair);

	/* Checa se recebeu o IP nos parâmetros. */
	if (argc < 2) {
		perror("Falta argumento: endereço de IP do servidor.");
		return EXIT_FAILURE;
	}

	/* Cria o socket. */
	sock = socket(PF_INET, SOCK_DGRAM, 0);
	if (sock == -1) {
		perror("Não conseguiu criar o socket.");
		return EXIT_FAILURE;
	}

	/* Cria o endereço do servidor onde vai conectar. */
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = inet_addr(argv[1]);
	memset(&addr.sin_zero, 0, 8);

	/*Inicia variaveis globais.*/
	soma = 0.0;
	menorPing = 50000.0;
	maiorPing = 0.0;

	/* Envia LEN pacotes para o servidor e escreve o eco. */
	for (i = 0; 1; i++) {
		/*Envia msg ao servidor*/
		aux = sendto(sock, msg, LEN, 0, (struct sockaddr *) &addr, size);
		if (aux < 0) {
			perror("Erro ao enviar mensagem");
			return EXIT_FAILURE;
		}
		/*Ve o tempo que foi enviado*/
		aux = gettimeofday(&tempo,NULL);
		if (aux < 0) {
			perror("Erro ao pegar tempo de envio");
			return EXIT_FAILURE;
		}
		/*Espera resposta do servidor*/
		aux = recvfrom(sock, msg, LEN, 0, (struct sockaddr *) &addr, &size);
		if (aux < 0) {
			perror("Erro ao receber mensagem");
			return EXIT_FAILURE;
		}
		/*Ve o tempo em que foi recebida resposta*/
		aux = gettimeofday(&tempo2,NULL);
		if (aux < 0) {
			perror("Erro ao pegar tempo de retorno");
			return EXIT_FAILURE;
		}

		/*Calcula o tempo do ping em milisegundos*/
		tempoPing = (float) ((((tempo2.tv_sec*1000000)+(tempo2.tv_usec))
				 - ((tempo.tv_sec*1000000)+(tempo.tv_usec)))/1000.0);

		/*Soma os pings pra calcular a media*/
		soma += tempoPing;

		/*Calcula menor e maior pings*/
		if (tempoPing < menorPing){
			menorPing = tempoPing;
		}
		if (tempoPing > maiorPing){
			maiorPing = tempoPing;
		}

		/*Imprime o resultado do ping*/
		printf("PING %d recebido em %.3fms!\n", (i+1), tempoPing);

		/*Espera um segundo antes do proximo ping.*/
		sleep(1);

	}

	close(sock);

	return 0;
}
